package com.syjy.tunnelworker.senders.iml;


import com.syjy.DataExchangeException;
import com.syjy.container.ProtocolDataContainer;
import com.syjy.tunnelinfo.DataPoint;
import com.syjy.tunnelinfo.TunnelStatus;
import com.syjy.tunnelinfo.sendertunnelinfo.Sender104TcpTunnelInfo;
import com.syjy.tunnelworker.BaseProtocolTunnel;
import com.syjy.tunnelworker.senders.DataSenderInterface;
import com.syjy.tunnelworker.workassist.SingleThreadPoolExecutorUtil;
import io.netty.channel.Channel;
import wei.yigulu.iec104.nettyconfig.Iec104SlaverBuilder;
import wei.yigulu.iec104.util.SendDataFrameHelper;
import wei.yigulu.modbus.domain.datatype.ModbusDataTypeEnum;

import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 104转发的通道实体
 * <p>
 * 转发点表默认连续  遥信遥测分区
 *
 * @author: xiuwei
 * @version:
 */
public class Iec104TcpDataSender extends BaseProtocolTunnel<Sender104TcpTunnelInfo, Iec104SlaverBuilder> implements DataSenderInterface {


    /**
     * 遥测点位的对应关系
     */
    Map<Integer, DataPoint> ycDataPoints;


    /**
     * 遥信点位的对应关系
     */
    Map<Integer, DataPoint> yxDataPoints;


    /**
     * 顶层的构造方法
     *
     * @param tunnelInfo 通道信息
     */
    public Iec104TcpDataSender(Sender104TcpTunnelInfo tunnelInfo) {
        super(tunnelInfo);
    }

    @Override
    public Iec104TcpDataSender startTunnel() throws DataExchangeException {
        protocolTunnelContainer.addUpdateDateTask(this);
        try {
            SingleThreadPoolExecutorUtil.submitBySingleThreadExecutor(() -> {
                try {
                    this.protocolBuilder.create();
                } catch (Exception e) {
                    log.error("创建104Sender失败", e);
                    this.setTunnelStatus(TunnelStatus.LISTENPORTFAIL);
                }
            });
        } catch (Throwable e) {
            setTunnelStatus(TunnelStatus.LISTENPORTFAIL);
            log.error("104slaver通道创建时发生异常", e);
            throw new DataExchangeException(10010, "104slaver通道创建时发生异常");
        }
        if (!TunnelStatus.LISTENPORTFAIL.equals(getTunnelStatus())) {
            setTunnelStatus(TunnelStatus.LISTENPORTSUCCESS);
        }
        return this;
    }

    @Override
    public Iec104TcpDataSender buildTunnel() throws DataExchangeException {
        this.protocolBuilder = new MyIec104Slaver(this.tunnelInfo.getSelfPort());
        this.protocolBuilder.setIp(this.tunnelInfo.getSelfIp());
        this.protocolBuilder.setLog(log);
        this.protocolBuilder.getConfigInfoMap().put("yx", this.yxDataPoints);
        this.protocolBuilder.getConfigInfoMap().put("yc", this.ycDataPoints);
        this.setTunnelStatus(TunnelStatus.BUILT);
        protocolTunnelContainer.addTunnel(this);
        parseGatherDataPoint();
        log.info("成功创建Iec 104Tcp master通道对象：{}", this.tunnelInfo.getTunnelName());
        return this;
    }

    @Override
    public void parseGatherDataPoint() throws DataExchangeException {
        log.info("解析通道下所需点位");
        List<DataPoint> dataPoints = this.getTunnelInfo().getDataPoints();
        if (dataPoints == null || dataPoints.size() == 0) {
            return;
        }
        yxDataPoints = new HashMap<>();
        ycDataPoints = new HashMap<>();
        for (DataPoint d : dataPoints) {
            if (ModbusDataTypeEnum.A16.equals(d.getDataType())) {
                yxDataPoints.put(d.getProtocolPoint(), d);
            } else {
                ycDataPoints.put(d.getProtocolPoint(), d);
            }
        }
    }

    @Override
    public BaseProtocolTunnel tunnelStop() throws DataExchangeException {
        if (this.protocolBuilder != null) {
            this.protocolBuilder.stop();
        }
        log.info("关闭IEC104通道：{}", this.tunnelInfo.getTunnelName());
        return super.tunnelStop();
    }

    @Override
    public void updateData2Protocol() throws DataExchangeException {
        if (this.protocolBuilder.getChannels().size() == 0) {
            log.trace("当前没有master联入");
            setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDNOCONN);
            return;
        }
        log.info("向该通道的所有连接发送数据");
        ProtocolDataContainer dataContainer = ProtocolDataContainer.getInstance();
        Map<Integer, Number> yc = new HashMap<>();
        this.ycDataPoints.forEach((k, v) -> yc.put(k, dataContainer.getNumber(v.getId()).multiply(BigDecimal.valueOf(v.getMag()))));
        Map<Integer, Boolean> yx = new HashMap<>();
        this.yxDataPoints.forEach((k, v) -> yx.put(k, dataContainer.getBoolean(v.getId())));
        for (Channel channel : this.protocolBuilder.getChannels()) {
            try {
                SendDataFrameHelper.sendYxDataFrameDiscontinuity(channel, yx, getTunnelInfo().getPublicAddress(), 3, log);
                SendDataFrameHelper.sendYcDataFrameDiscontinuity(channel, yc, getTunnelInfo().getPublicAddress(), 3, log);
            } catch (Exception e) {
                log.error("104通道发送数据时发生异常", e);
                e.printStackTrace();
                throw new DataExchangeException(10008, "104通道发送数据时发生异常");
            }
        }
    }

    class MyIec104Slaver extends Iec104SlaverBuilder {
        public MyIec104Slaver(int port) {
            super(port);
        }
        public void connected(InetSocketAddress ipSocket) {
            setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONN);
        }
    }


}
